home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / language / harvest.cpt / Harvest C / Tcl 6.2 / tclBasic.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-13  |  27.2 KB  |  1,062 lines

  1. #ifdef macintosh
  2. #    pragma segment tclBasic
  3. #endif
  4.  
  5. /* 
  6.  * tclBasic.c --
  7.  *
  8.  *    Contains the basic facilities for TCL command interpretation,
  9.  *    including interpreter creation and deletion, command creation
  10.  *    and deletion, and command parsing and execution.
  11.  *
  12.  * Copyright 1987-1991 Regents of the University of California
  13.  * Permission to use, copy, modify, and distribute this
  14.  * software and its documentation for any purpose and without
  15.  * fee is hereby granted, provided that the above copyright
  16.  * notice appear in all copies.  The University of California
  17.  * makes no representations about the suitability of this
  18.  * software for any purpose.  It is provided "as is" without
  19.  * express or implied warranty.
  20.  */
  21.  
  22. #ifndef lint
  23. static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclBasic.c,v 1.128 91/10/31 16:41:13 ouster Exp $ SPRITE (Berkeley)";
  24. #endif
  25.  
  26. #include "tclInt.h"
  27.  
  28. /*
  29.  * The following structure defines all of the commands in the Tcl core,
  30.  * and the C procedures that execute them.
  31.  */
  32.  
  33. typedef struct {
  34.     char *name;            /* Name of command. */
  35.     Tcl_CmdProc *proc;        /* Procedure that executes command. */
  36.     } CmdInfo;
  37.  
  38. /*
  39.  * Built-in commands, and the procedures associated with them:
  40.  */
  41.  
  42. static CmdInfo builtInCmds[] = {
  43.     /*
  44.      * Commands in the generic core:
  45.      */
  46.  
  47.     {"append",        Tcl_AppendCmd},
  48.     {"array",        Tcl_ArrayCmd},
  49.     {"break",        Tcl_BreakCmd},
  50.     {"case",        Tcl_CaseCmd},
  51.     {"catch",        Tcl_CatchCmd},
  52.     {"concat",        Tcl_ConcatCmd},
  53.     {"continue",    Tcl_ContinueCmd},
  54.     {"error",        Tcl_ErrorCmd},
  55.     {"eval",        Tcl_EvalCmd},
  56.     {"expr",        Tcl_ExprCmd},
  57.     {"for",            Tcl_ForCmd},
  58.     {"foreach",        Tcl_ForeachCmd},
  59.     {"format",        Tcl_FormatCmd},
  60.     {"global",        Tcl_GlobalCmd},
  61.     {"if",            Tcl_IfCmd},
  62.     {"incr",        Tcl_IncrCmd},
  63.     {"info",        Tcl_InfoCmd},
  64.     {"join",        Tcl_JoinCmd},
  65.     {"lappend",        Tcl_LappendCmd},
  66.     {"lindex",        Tcl_LindexCmd},
  67.     {"linsert",        Tcl_LinsertCmd},
  68.     {"list",        Tcl_ListCmd},
  69.     {"llength",        Tcl_LlengthCmd},
  70.     {"lrange",        Tcl_LrangeCmd},
  71.     {"lreplace",    Tcl_LreplaceCmd},
  72.     {"lsearch",        Tcl_LsearchCmd},
  73.     {"lsort",        Tcl_LsortCmd},
  74.     {"proc",        Tcl_ProcCmd},
  75.     {"regexp",        Tcl_RegexpCmd},
  76.     {"regsub",        Tcl_RegsubCmd},
  77.     {"rename",        Tcl_RenameCmd},
  78.     {"return",        Tcl_ReturnCmd},
  79.     {"scan",        Tcl_ScanCmd},
  80.     {"set",            Tcl_SetCmd},
  81.     {"split",        Tcl_SplitCmd},
  82.     {"string",        Tcl_StringCmd},
  83.     {"trace",        Tcl_TraceCmd},
  84.     {"unset",        Tcl_UnsetCmd},
  85.     {"uplevel",        Tcl_UplevelCmd},
  86.     {"upvar",        Tcl_UpvarCmd},
  87.     {"while",        Tcl_WhileCmd},
  88.  
  89.     /*
  90.      * Commands in the UNIX core:
  91.      */
  92.  
  93. #ifndef TCL_GENERIC_ONLY
  94. #ifndef macintosh
  95.     {"cd",            Tcl_CdCmd},
  96.     {"exec",        Tcl_ExecCmd},
  97.     {"pwd",            Tcl_PwdCmd},
  98. #endif
  99.     {"close",        Tcl_CloseCmd},
  100.     {"eof",            Tcl_EofCmd},
  101.     {"exit",        Tcl_ExitCmd},
  102.     {"file",        Tcl_FileCmd},
  103.     {"flush",        Tcl_FlushCmd},
  104.     {"gets",        Tcl_GetsCmd},
  105.     {"glob",        Tcl_GlobCmd},
  106.     {"open",        Tcl_OpenCmd},
  107.     {"puts",        Tcl_PutsCmd},
  108.     {"read",        Tcl_ReadCmd},
  109.     {"seek",        Tcl_SeekCmd},
  110.     {"source",        Tcl_SourceCmd},
  111.     {"tell",        Tcl_TellCmd},
  112.     {"time",        Tcl_TimeCmd},
  113. #endif /* TCL_GENERIC_ONLY */
  114.     {NULL,        (Tcl_CmdProc *) NULL}
  115. };
  116.  
  117. /*
  118.  *----------------------------------------------------------------------
  119.  *
  120.  * Tcl_CreateInterp --
  121.  *
  122.  *    Create a _new TCL command interpreter.
  123.  *
  124.  * Results:
  125.  *    The return value is a token for the interpreter, which may be
  126.  *    used in calls to procedures like Tcl_CreateCmd, Tcl_Eval, or
  127.  *    Tcl_DeleteInterp.
  128.  *
  129.  * Side effects:
  130.  *    The command interpreter is initialized with an empty variable
  131.  *    table and the built-in commands.
  132.  *
  133.  *----------------------------------------------------------------------
  134.  */
  135.  
  136. Tcl_Interp *
  137. Tcl_CreateInterp()
  138. {
  139.     register Interp *iPtr;
  140.     register Command *cmdPtr;
  141.     register CmdInfo *cmdInfoPtr;
  142.     int i;
  143.  
  144.     iPtr = (Interp *) ckalloc(sizeof(Interp));
  145.     iPtr->result = iPtr->resultSpace;
  146.     iPtr->freeProc = 0;
  147.     iPtr->errorLine = 0;
  148.     Tcl_InitHashTable(&iPtr->commandTable, TCL_STRING_KEYS);
  149.     Tcl_InitHashTable(&iPtr->globalTable, TCL_STRING_KEYS);
  150.     iPtr->numLevels = 0;
  151.     iPtr->framePtr = NULL;
  152.     iPtr->varFramePtr = NULL;
  153.     iPtr->activeTracePtr = NULL;
  154.     iPtr->numEvents = 0;
  155.     iPtr->events = NULL;
  156.     iPtr->curEvent = 0;
  157.     iPtr->curEventNum = 0;
  158.     iPtr->revPtr = NULL;
  159.     iPtr->historyFirst = NULL;
  160.     iPtr->revDisables = 1;
  161.     iPtr->evalFirst = iPtr->evalLast = NULL;
  162.     iPtr->appendResult = NULL;
  163.     iPtr->appendAvl = 0;
  164.     iPtr->appendUsed = 0;
  165.     iPtr->numFiles = 0;
  166.     iPtr->filePtrArray = NULL;
  167.     for (i = 0; i < NUM_REGEXPS; i++) {
  168.         iPtr->patterns[i] = NULL;
  169.         iPtr->regexps[i] = NULL;
  170.         }
  171.     iPtr->cmdCount = 0;
  172.     iPtr->noEval = 0;
  173.     iPtr->scriptFile = NULL;
  174.     iPtr->flags = 0;
  175.     iPtr->tracePtr = NULL;
  176.     iPtr->resultSpace[0] = 0;
  177.  
  178.     /*
  179.      * Create the built-in commands.  Do it here, rather than calling
  180.      * Tcl_CreateCommand, because it's faster (there's no need to
  181.      * check for a pre-existing command by the same name).
  182.      */
  183.  
  184.     for (cmdInfoPtr = builtInCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {
  185.     int _new;
  186.     Tcl_HashEntry *hPtr;
  187.  
  188.     hPtr = Tcl_CreateHashEntry(&iPtr->commandTable,
  189.         cmdInfoPtr->name, &_new);
  190.     if (_new) {
  191.         cmdPtr = (Command *) ckalloc(sizeof(Command));
  192.         cmdPtr->proc = cmdInfoPtr->proc;
  193.         cmdPtr->clientData = (ClientData) NULL;
  194.         cmdPtr->deleteProc = NULL;
  195.         Tcl_SetHashValue(hPtr, cmdPtr);
  196.     }
  197.     }
  198.  
  199. #ifndef TCL_GENERIC_ONLY
  200.     TclSetupEnv((Tcl_Interp *) iPtr);
  201. #endif
  202.  
  203.     return (Tcl_Interp *) iPtr;
  204. }
  205.  
  206. /*
  207.  *----------------------------------------------------------------------
  208.  *
  209.  * Tcl_DeleteInterp --
  210.  *
  211.  *    Delete an interpreter and free up all of the resources associated
  212.  *    with it.
  213.  *
  214.  * Results:
  215.  *    None.
  216.  *
  217.  * Side effects:
  218.  *    The interpreter is destroyed.  The caller should never again
  219.  *    use the interp token.
  220.  *
  221.  *----------------------------------------------------------------------
  222.  */
  223.  
  224. void
  225. Tcl_DeleteInterp(interp)
  226.     Tcl_Interp *interp;        /* Token for command interpreter (returned
  227.                  * by a previous call to Tcl_CreateInterp). */
  228. {
  229.     Interp *iPtr = (Interp *) interp;
  230.     Tcl_HashEntry *hPtr;
  231.     Tcl_HashSearch search;
  232.     register Command *cmdPtr;
  233.     int i;
  234.  
  235.     /*
  236.      * If the interpreter is in use, delay the deletion until later.
  237.      */
  238.  
  239.     iPtr->flags |= DELETED;
  240.     if (iPtr->numLevels != 0) {
  241.     return;
  242.     }
  243.  
  244.     /*
  245.      * Free up any remaining resources associated with the
  246.      * interpreter.
  247.      */
  248.  
  249.     for (hPtr = Tcl_FirstHashEntry(&iPtr->commandTable, &search);
  250.         hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
  251.     cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
  252.     if (cmdPtr->deleteProc != NULL) { 
  253.         (*cmdPtr->deleteProc)(cmdPtr->clientData);
  254.     }
  255.     ckfree((char *) cmdPtr);
  256.     }
  257.     Tcl_DeleteHashTable(&iPtr->commandTable);
  258.     TclDeleteVars(iPtr, &iPtr->globalTable);
  259.     if (iPtr->events != NULL) {
  260.     int i;
  261.  
  262.     for (i = 0; i < iPtr->numEvents; i++) {
  263.         ckfree(iPtr->events[i].command);
  264.     }
  265.     ckfree((char *) iPtr->events);
  266.     }
  267.     while (iPtr->revPtr != NULL) {
  268.     HistoryRev *nextPtr = iPtr->revPtr->nextPtr;
  269.  
  270.     ckfree((char *) iPtr->revPtr);
  271.     iPtr->revPtr = nextPtr;
  272.     }
  273.     if (iPtr->appendResult != NULL) {
  274.     ckfree(iPtr->appendResult);
  275.     }
  276. #ifndef TCL_GENERIC_ONLY
  277.     if (iPtr->numFiles > 0) {
  278.     for (i = 0; i < iPtr->numFiles; i++) {
  279.         OpenFile *filePtr;
  280.     
  281.         filePtr = iPtr->filePtrArray[i];
  282.         if (filePtr == NULL) {
  283.         continue;
  284.         }
  285.         if (i >= 3) {
  286.         fclose(filePtr->f);
  287.         if (filePtr->f2 != NULL) {
  288.             fclose(filePtr->f2);
  289.         }
  290.         if (filePtr->numPids > 0) {
  291.             Tcl_DetachPids(filePtr->numPids, filePtr->pidPtr);
  292.             ckfree((char *) filePtr->pidPtr);
  293.         }
  294.         }
  295.         ckfree((char *) filePtr);
  296.     }
  297.     ckfree((char *) iPtr->filePtrArray);
  298.     }
  299. #endif
  300.     for (i = 0; i < NUM_REGEXPS; i++) {
  301.     if (iPtr->patterns[i] == NULL) {
  302.         break;
  303.     }
  304.     ckfree(iPtr->patterns[i]);
  305.     ckfree((char *) iPtr->regexps[i]);
  306.     }
  307.     while (iPtr->tracePtr != NULL) {
  308.     Trace *nextPtr = iPtr->tracePtr->nextPtr;
  309.  
  310.     ckfree((char *) iPtr->tracePtr);
  311.     iPtr->tracePtr = nextPtr;
  312.     }
  313.     ckfree((char *) iPtr);
  314. }
  315.  
  316. /*
  317.  *----------------------------------------------------------------------
  318.  *
  319.  * Tcl_CreateCommand --
  320.  *
  321.  *    Define a _new command in a command table.
  322.  *
  323.  * Results:
  324.  *    None.
  325.  *
  326.  * Side effects:
  327.  *    If a command named cmdName already exists for interp, it is
  328.  *    deleted.  In the future, when cmdName is seen as the name of
  329.  *    a command by Tcl_Eval, proc will be called.  When the command
  330.  *    is deleted from the table, deleteProc will be called.  See the
  331.  *    manual entry for details on the calling sequence.
  332.  *
  333.  *----------------------------------------------------------------------
  334.  */
  335.  
  336. void
  337. Tcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc)
  338.     Tcl_Interp *interp;        /* Token for command interpreter (returned
  339.                  * by a previous call to Tcl_CreateInterp). */
  340.     char *cmdName;        /* Name of command. */
  341.     Tcl_CmdProc *proc;        /* Command procedure to associate with
  342.                  * cmdName. */
  343.     ClientData clientData;    /* Arbitrary one-word value to pass to proc. */
  344.     Tcl_CmdDeleteProc *deleteProc;
  345.                 /* If not NULL, gives a procedure to call when
  346.                  * this command is deleted. */
  347. {
  348.     Interp *iPtr = (Interp *) interp;
  349.     register Command *cmdPtr;
  350.     Tcl_HashEntry *hPtr;
  351.     int _new;
  352.  
  353.     hPtr = Tcl_CreateHashEntry(&iPtr->commandTable, cmdName, &_new);
  354.     if (!_new) {
  355.     /*
  356.      * Command already exists:  delete the old one.
  357.      */
  358.  
  359.     cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
  360.     if (cmdPtr->deleteProc != NULL) {
  361.         (*cmdPtr->deleteProc)(cmdPtr->clientData);
  362.     }
  363.     } else {
  364.     cmdPtr = (Command *) ckalloc(sizeof(Command));
  365.     Tcl_SetHashValue(hPtr, cmdPtr);
  366.     }
  367.     cmdPtr->proc = proc;
  368.     cmdPtr->clientData = clientData;
  369.     cmdPtr->deleteProc = deleteProc;
  370. }
  371.  
  372. /*
  373.  *----------------------------------------------------------------------
  374.  *
  375.  * Tcl_DeleteCommand --
  376.  *
  377.  *    Remove the given command from the given interpreter.
  378.  *
  379.  * Results:
  380.  *    0 is returned if the command was deleted successfully.
  381.  *    -1 is returned if there didn't exist a command by that
  382.  *    name.
  383.  *
  384.  * Side effects:
  385.  *    CmdName will no longer be recognized as a valid command for
  386.  *    interp.
  387.  *
  388.  *----------------------------------------------------------------------
  389.  */
  390.  
  391. int
  392. Tcl_DeleteCommand(interp, cmdName)
  393.     Tcl_Interp *interp;        /* Token for command interpreter (returned
  394.                  * by a previous call to Tcl_CreateInterp). */
  395.     char *cmdName;        /* Name of command to remove. */
  396. {
  397.     Interp *iPtr = (Interp *) interp;
  398.     Tcl_HashEntry *hPtr;
  399.     Command *cmdPtr;
  400.  
  401.     hPtr = Tcl_FindHashEntry(&iPtr->commandTable, cmdName);
  402.     if (hPtr == NULL) {
  403.     return -1;
  404.     }
  405.     cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
  406.     if (cmdPtr->deleteProc != NULL) {
  407.     (*cmdPtr->deleteProc)(cmdPtr->clientData);
  408.     }
  409.     ckfree((char *) cmdPtr);
  410.     Tcl_DeleteHashEntry(hPtr);
  411.     return 0;
  412. }
  413.  
  414. /*
  415.  *-----------------------------------------------------------------
  416.  *
  417.  * Tcl_Eval --
  418.  *
  419.  *    Parse and execute a command in the Tcl language.
  420.  *
  421.  * Results:
  422.  *    The return value is one of the return codes defined in tcl.hd
  423.  *    (such as TCL_OK), and interp->result contains a string value
  424.  *    to supplement the return code.  The value of interp->result
  425.  *    will persist only until the next call to Tcl_Eval:  copy it or
  426.  *    lose it! *TermPtr is filled in with the character just after
  427.  *    the last one that was part of the command (usually a NULL
  428.  *    character or a closing bracket).
  429.  *
  430.  * Side effects:
  431.  *    Almost certainly;  depends on the command.
  432.  *
  433.  *-----------------------------------------------------------------
  434.  */
  435.  
  436. int
  437. Tcl_Eval(interp, cmd, flags, termPtr)
  438.     Tcl_Interp *interp;        /* Token for command interpreter (returned
  439.                  * by a previous call to Tcl_CreateInterp). */
  440.     char *cmd;            /* Pointer to TCL command to interpret. */
  441.     int flags;            /* OR-ed combination of flags like
  442.                  * TCL_BRACKET_TERM and TCL_RECORD_BOUNDS. */
  443.     char **termPtr;        /* If non-NULL, fill in the address it points
  444.                  * to with the address of the char. just after
  445.                  * the last one that was part of cmd.  See
  446.                  * the man page for details on this. */
  447. {
  448.     /*
  449.      * The storage immediately below is used to generate a copy
  450.      * of the command, after all argument substitutions.  Pv will
  451.      * contain the argv values passed to the command procedure.
  452.      */
  453.  
  454. #   define NUM_CHARS 200
  455.     char copyStorage[NUM_CHARS];
  456.     ParseValue pv;
  457.     char *oldBuffer;
  458.  
  459.     /*
  460.      * This procedure generates an (argv, argc) array for the command,
  461.      * It starts out with stack-allocated space but uses dynamically-
  462.      * allocated storage to increase it if needed.
  463.      */
  464.  
  465. #   define NUM_ARGS 10
  466.     char *(argStorage[NUM_ARGS]);
  467.     char **argv = argStorage;
  468.     int argc;
  469.     int argSize = NUM_ARGS;
  470.  
  471.     register char *src;            /* Points to current character
  472.                      * in cmd. */
  473.     char termChar;            /* Return when this character is found
  474.                      * (either ']' or '\0').  Zero means
  475.                      * that newlines terminate commands. */
  476.     int result;                /* Return value. */
  477.     register Interp *iPtr = (Interp *) interp;
  478.     Tcl_HashEntry *hPtr;
  479.     Command *cmdPtr;
  480.     char *dummy;            /* Make termPtr point here if it was
  481.                      * originally NULL. */
  482.     char *cmdStart;            /* Points to first non-blank char. in
  483.                      * command (used in calling trace
  484.                      * procedures). */
  485.     char *ellipsis = "";        /* Used in setting errorInfo variable;
  486.                      * set to "..." to indicate that not
  487.                      * all of offending command is included
  488.                      * in errorInfo.  "" means that the
  489.                      * command is all there. */
  490.     register Trace *tracePtr;
  491.  
  492.     /*
  493.      * Initialize the result to an empty string and clear out any
  494.      * error information.  This makes sure that we return an empty
  495.      * result if there are no commands in the command string.
  496.      */
  497.  
  498.     Tcl_FreeResult((Tcl_Interp *) iPtr);
  499.     iPtr->result = iPtr->resultSpace;
  500.     iPtr->resultSpace[0] = 0;
  501.     result = TCL_OK;
  502.  
  503.     /*
  504.      * Check depth of nested calls to Tcl_Eval:  if this gets too large,
  505.      * it's probably because of an infinite loop somewhere.
  506.      */
  507.  
  508.     iPtr->numLevels++;
  509.     if (iPtr->numLevels > MAX_NESTING_DEPTH) {
  510.     iPtr->result =  "too many nested calls to Tcl_Eval (infinite loop?)";
  511.     return TCL_ERROR;
  512.     }
  513.  
  514.     /*
  515.      * Initialize the area in which command copies will be assembled.
  516.      */
  517.  
  518.     pv.buffer = copyStorage;
  519.     pv.end = copyStorage + NUM_CHARS - 1;
  520.     pv.expandProc = TclExpandParseValue;
  521.     pv.clientData = (ClientData) NULL;
  522.  
  523.     src = cmd;
  524.     if (flags & TCL_BRACKET_TERM) {
  525.     termChar = ']';
  526.     } else {
  527.     termChar = 0;
  528.     }
  529.     if (termPtr == NULL) {
  530.     termPtr = &dummy;
  531.     }
  532.     *termPtr = src;
  533.     cmdStart = src;
  534.  
  535.     /*
  536.      * There can be many sub-commands (separated by semi-colons or
  537.      * newlines) in one command string.  This outer loop iterates over
  538.      * individual commands.
  539.      */
  540.  
  541.     while (*src != termChar) {
  542.     iPtr->flags &= ~(ERR_IN_PROGRESS | ERROR_CODE_SET);
  543.  
  544.     /*
  545.      * Skim off leading white space and semi-colons, and skip
  546.      * comments.
  547.      */
  548.  
  549.     while (1) {
  550.         register char c = *src;
  551.  
  552.         if ((CHAR_TYPE(c) != TCL_SPACE) && (c != ';') && (c != '\n')) {
  553.         break;
  554.         }
  555.         src += 1;
  556.     }
  557.     if (*src == '#') {
  558.         for (src++; *src != 0; src++) {
  559.         if (*src == '\n') {
  560.             src++;
  561.             break;
  562.         }
  563.         }
  564.         continue;
  565.     }
  566.     cmdStart = src;
  567.  
  568.     /*
  569.      * Parse the words of the command, generating the argc and
  570.      * argv for the command procedure.  May have to call
  571.      * TclParseWords several times, expanding the argv array
  572.      * between calls.
  573.      */
  574.  
  575.     pv.next = oldBuffer = pv.buffer;
  576.     argc = 0;
  577.     while (1) {
  578.         int newArgs, maxArgs;
  579.         char **newArgv;
  580.         int i;
  581.  
  582.         /*
  583.          * Note:  the "- 2" below guarantees that we won't use the
  584.          * last two argv slots here.  One is for a NULL pointer to
  585.          * mark the end of the list, and the other is to leave room
  586.          * for inserting the command name "unknown" as the first
  587.          * argument (see below).
  588.          */
  589.  
  590.         maxArgs = argSize - argc - 2;
  591.         result = TclParseWords((Tcl_Interp *) iPtr, src, flags,
  592.             maxArgs, termPtr, &newArgs, &argv[argc], &pv);
  593.         src = *termPtr;
  594.         if (result != TCL_OK) {
  595.         ellipsis = "...";
  596.         goto done;
  597.         }
  598.  
  599.         /*
  600.          * Careful!  Buffer space may have gotten reallocated while
  601.          * parsing words.  If this happened, be sure to update all
  602.          * of the older argv pointers to refer to the _new space.
  603.          */
  604.  
  605.         if (oldBuffer != pv.buffer) {
  606.         int i;
  607.  
  608.         for (i = 0; i < argc; i++) {
  609.             argv[i] = pv.buffer + (argv[i] - oldBuffer);
  610.         }
  611.         oldBuffer = pv.buffer;
  612.         }
  613.         argc += newArgs;
  614.         if (newArgs < maxArgs) {
  615.         argv[argc] = (char *) NULL;
  616.         break;
  617.         }
  618.  
  619.         /*
  620.          * Args didn't all fit in the current array.  Make it bigger.
  621.          */
  622.  
  623.         argSize *= 2;
  624.         newArgv = (char **)
  625.             ckalloc((unsigned) argSize * sizeof(char *));
  626.         for (i = 0; i < argc; i++) {
  627.         newArgv[i] = argv[i];
  628.         }
  629.         if (argv != argStorage) {
  630.         ckfree((char *) argv);
  631.         }
  632.         argv = newArgv;
  633.     }
  634.  
  635.     /*
  636.      * If this is an empty command (or if we're just parsing
  637.      * commands without evaluating them), then just skip to the
  638.      * next command.
  639.      */
  640.  
  641.     if ((argc == 0) || iPtr->noEval) {
  642.         continue;
  643.     }
  644.     argv[argc] = NULL;
  645.  
  646.     /*
  647.      * Save information for the history module, if needed.
  648.      */
  649.  
  650.     if (flags & TCL_RECORD_BOUNDS) {
  651.         iPtr->evalFirst = cmdStart;
  652.         iPtr->evalLast = src-1;
  653.     }
  654.  
  655.     /*
  656.      * Find the procedure to execute this command.  If there isn't
  657.      * one, then see if there is a command "unknown".  If so,
  658.      * invoke it instead, passing it the words of the original
  659.      * command as arguments.
  660.      */
  661.  
  662.     hPtr = Tcl_FindHashEntry(&iPtr->commandTable, argv[0]);
  663.     if (hPtr == NULL) {
  664.         int i;
  665.  
  666.         hPtr = Tcl_FindHashEntry(&iPtr->commandTable, "unknown");
  667.         if (hPtr == NULL) {
  668.         Tcl_ResetResult(interp);
  669.         Tcl_AppendResult(interp, "invalid command name: \"",
  670.             argv[0], "\"", (char *) NULL);
  671.         result = TCL_ERROR;
  672.         goto done;
  673.         }
  674.         for (i = argc; i >= 0; i--) {
  675.         argv[i+1] = argv[i];
  676.         }
  677.         argv[0] = "unknown";
  678.         argc++;
  679.     }
  680.     cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
  681.  
  682.     /*
  683.      * Call trace procedures, if any.
  684.      */
  685.  
  686.     for (tracePtr = iPtr->tracePtr; tracePtr != NULL;
  687.         tracePtr = tracePtr->nextPtr) {
  688.         char saved;
  689.  
  690.         if (tracePtr->level < iPtr->numLevels) {
  691.         continue;
  692.         }
  693.         saved = *src;
  694.         *src = 0;
  695.         (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
  696.             cmdStart, cmdPtr->proc, cmdPtr->clientData, argc, argv);
  697.         *src = saved;
  698.     }
  699.  
  700.     /*
  701.      * At long last, invoke the command procedure.  Reset the
  702.      * result to its default empty value first (it could have
  703.      * gotten changed by earlier commands in the same command
  704.      * string).
  705.      */
  706.  
  707.     iPtr->cmdCount++;
  708.     Tcl_FreeResult(iPtr);
  709.     iPtr->result = iPtr->resultSpace;
  710.     iPtr->resultSpace[0] = 0;
  711.     result = (*cmdPtr->proc)(cmdPtr->clientData, interp, argc, argv);
  712.     if (result != TCL_OK) {
  713.         break;
  714.     }
  715.     }
  716.  
  717.     /*
  718.      * Free up any extra resources that were allocated.
  719.      */
  720.  
  721.     done:
  722.     if (pv.buffer != copyStorage) {
  723.     ckfree((char *) pv.buffer);
  724.     }
  725.     if (argv != argStorage) {
  726.     ckfree((char *) argv);
  727.     }
  728.     iPtr->numLevels--;
  729.     if (iPtr->numLevels == 0) {
  730.     if (result == TCL_RETURN) {
  731.         result = TCL_OK;
  732.     }
  733.     if ((result != TCL_OK) && (result != TCL_ERROR)) {
  734.         Tcl_ResetResult(interp);
  735.         if (result == TCL_BREAK) {
  736.         iPtr->result = "invoked \"break\" outside of a loop";
  737.         } else if (result == TCL_CONTINUE) {
  738.         iPtr->result = "invoked \"continue\" outside of a loop";
  739.         } else {
  740.         iPtr->result = iPtr->resultSpace;
  741.         sprintf(iPtr->resultSpace, "command returned bad code: %d",
  742.             result);
  743.         }
  744.         result = TCL_ERROR;
  745.     }
  746.     if (iPtr->flags & DELETED) {
  747.         Tcl_DeleteInterp(interp);
  748.     }
  749.     }
  750.  
  751.     /*
  752.      * If an error occurred, record information about what was being
  753.      * executed when the error occurred.
  754.      */
  755.  
  756.     if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
  757.     int numChars;
  758.     register char *p;
  759.  
  760.     /*
  761.      * Compute the line number where the error occurred.
  762.      */
  763.  
  764.     iPtr->errorLine = 1;
  765.     for (p = cmd; p != cmdStart; p++) {
  766.         if (*p == '\n') {
  767.         iPtr->errorLine++;
  768.         }
  769.     }
  770.     for ( ; isspace(*p) || (*p == ';'); p++) {
  771.         if (*p == '\n') {
  772.         iPtr->errorLine++;
  773.         }
  774.     }
  775.  
  776.     /*
  777.      * Figure out how much of the command to print in the error
  778.      * message (up to a certain number of characters, or up to
  779.      * the first _new-line).
  780.      */
  781.  
  782.     numChars = src - cmdStart;
  783.     if (numChars > (NUM_CHARS-50)) {
  784.         numChars = NUM_CHARS-50;
  785.         ellipsis = " ...";
  786.     }
  787.  
  788.     if (!(iPtr->flags & ERR_IN_PROGRESS)) {
  789.         sprintf(copyStorage, "\n    while executing\n\"%.*s%s\"",
  790.             numChars, cmdStart, ellipsis);
  791.     } else {
  792.         sprintf(copyStorage, "\n    invoked from within\n\"%.*s%s\"",
  793.             numChars, cmdStart, ellipsis);
  794.     }
  795.     Tcl_AddErrorInfo(interp, copyStorage);
  796.     iPtr->flags &= ~ERR_ALREADY_LOGGED;
  797.     } else {
  798.     iPtr->flags &= ~ERR_ALREADY_LOGGED;
  799.     }
  800.     return result;
  801. }
  802.  
  803. /*
  804.  *----------------------------------------------------------------------
  805.  *
  806.  * Tcl_CreateTrace --
  807.  *
  808.  *    Arrange for a procedure to be called to trace command execution.
  809.  *
  810.  * Results:
  811.  *    The return value is a token for the trace, which may be passed
  812.  *    to Tcl_DeleteTrace to eliminate the trace.
  813.  *
  814.  * Side effects:
  815.  *    From now on, proc will be called just before a command procedure
  816.  *    is called to execute a Tcl command.  Calls to proc will have the
  817.  *    following form:
  818.  *
  819.  *    void
  820.  *    proc(clientData, interp, level, command, cmdProc, cmdClientData,
  821.  *        argc, argv)
  822.  *        ClientData clientData;
  823.  *        Tcl_Interp *interp;
  824.  *        int level;
  825.  *        char *command;
  826.  *        int (*cmdProc)();
  827.  *        ClientData cmdClientData;
  828.  *        int argc;
  829.  *        char **argv;
  830.  *    {
  831.  *    }
  832.  *
  833.  *    The clientData and interp arguments to proc will be the same
  834.  *    as the corresponding arguments to this procedure.  Level gives
  835.  *    the nesting level of command interpretation for this interpreter
  836.  *    (0 corresponds to top level).  Command gives the ASCII text of
  837.  *    the raw command, cmdProc and cmdClientData give the procedure that
  838.  *    will be called to process the command and the ClientData value it
  839.  *    will receive, and argc and argv give the arguments to the
  840.  *    command, after any argument parsing and substitution.  Proc
  841.  *    does not return a value.
  842.  *
  843.  *----------------------------------------------------------------------
  844.  */
  845.  
  846. Tcl_Trace
  847. Tcl_CreateTrace(interp, level, proc, clientData)
  848.     Tcl_Interp *interp;        /* Interpreter in which to create the trace. */
  849.     int level;            /* Only call proc for commands at nesting level
  850.                  * <= level (1 => top level). */
  851.     Tcl_CmdTraceProc *proc;    /* Procedure to call before executing each
  852.                  * command. */
  853.     ClientData clientData;    /* Arbitrary one-word value to pass to proc. */
  854. {
  855.     register Trace *tracePtr;
  856.     register Interp *iPtr = (Interp *) interp;
  857.  
  858.     tracePtr = (Trace *) ckalloc(sizeof(Trace));
  859.     tracePtr->level = level;
  860.     tracePtr->proc = proc;
  861.     tracePtr->clientData = clientData;
  862.     tracePtr->nextPtr = iPtr->tracePtr;
  863.     iPtr->tracePtr = tracePtr;
  864.  
  865.     return (Tcl_Trace) tracePtr;
  866. }
  867.  
  868. /*
  869.  *----------------------------------------------------------------------
  870.  *
  871.  * Tcl_DeleteTrace --
  872.  *
  873.  *    Remove a trace.
  874.  *
  875.  * Results:
  876.  *    None.
  877.  *
  878.  * Side effects:
  879.  *    From now on there will be no more calls to the procedure given
  880.  *    in trace.
  881.  *
  882.  *----------------------------------------------------------------------
  883.  */
  884.  
  885. void
  886. Tcl_DeleteTrace(interp, trace)
  887.     Tcl_Interp *interp;        /* Interpreter that contains trace. */
  888.     Tcl_Trace trace;        /* Token for trace (returned previously by
  889.                  * Tcl_CreateTrace). */
  890. {
  891.     register Interp *iPtr = (Interp *) interp;
  892.     register Trace *tracePtr = (Trace *) trace;
  893.     register Trace *tracePtr2;
  894.  
  895.     if (iPtr->tracePtr == tracePtr) {
  896.     iPtr->tracePtr = tracePtr->nextPtr;
  897.     ckfree((char *) tracePtr);
  898.     } else {
  899.     for (tracePtr2 = iPtr->tracePtr; tracePtr2 != NULL;
  900.         tracePtr2 = tracePtr2->nextPtr) {
  901.         if (tracePtr2->nextPtr == tracePtr) {
  902.         tracePtr2->nextPtr = tracePtr->nextPtr;
  903.         ckfree((char *) tracePtr);
  904.         return;
  905.         }
  906.     }
  907.     }
  908. }
  909.  
  910. /*
  911.  *----------------------------------------------------------------------
  912.  *
  913.  * Tcl_AddErrorInfo --
  914.  *
  915.  *    Add information to a message being accumulated that describes
  916.  *    the current error.
  917.  *
  918.  * Results:
  919.  *    None.
  920.  *
  921.  * Side effects:
  922.  *    The contents of message are added to the "errorInfo" variable.
  923.  *    If Tcl_Eval has been called since the current value of errorInfo
  924.  *    was set, errorInfo is cleared before adding the _new message.
  925.  *
  926.  *----------------------------------------------------------------------
  927.  */
  928.  
  929. void
  930. Tcl_AddErrorInfo(interp, message)
  931.     Tcl_Interp *interp;        /* Interpreter to which error information
  932.                  * pertains. */
  933.     char *message;        /* Message to record. */
  934. {
  935.     register Interp *iPtr = (Interp *) interp;
  936.  
  937.     /*
  938.      * If an error is already being logged, then the _new errorInfo
  939.      * is the concatenation of the old info and the _new message.
  940.      * If this is the first piece of info for the error, then the
  941.      * _new errorInfo is the concatenation of the message in
  942.      * interp->result and the _new message.
  943.      */
  944.  
  945.     if (!(iPtr->flags & ERR_IN_PROGRESS)) {
  946.     Tcl_SetVar2(interp, "errorInfo", (char *) NULL, interp->result,
  947.         TCL_GLOBAL_ONLY);
  948.     iPtr->flags |= ERR_IN_PROGRESS;
  949.  
  950.     /*
  951.      * If the errorCode variable wasn't set by the code that generated
  952.      * the error, set it to "NONE".
  953.      */
  954.  
  955.     if (!(iPtr->flags & ERROR_CODE_SET)) {
  956.         (void) Tcl_SetVar2(interp, "errorCode", (char *) NULL, "NONE",
  957.             TCL_GLOBAL_ONLY);
  958.     }
  959.     }
  960.     Tcl_SetVar2(interp, "errorInfo", (char *) NULL, message,
  961.         TCL_GLOBAL_ONLY|TCL_APPEND_VALUE);
  962. }
  963.  
  964. /*
  965.  *----------------------------------------------------------------------
  966.  *
  967.  * Tcl_VarEval --
  968.  *
  969.  *    Given a variable number of string arguments, concatenate them
  970.  *    all together and execute the result as a Tcl command.
  971.  *
  972.  * Results:
  973.  *    A standard Tcl return result.  An error message or other
  974.  *    result may be left in interp->result.
  975.  *
  976.  * Side effects:
  977.  *    Depends on what was done by the command.
  978.  *
  979.  *----------------------------------------------------------------------
  980.  */
  981.     /* VARARGS2 */ /* ARGSUSED */
  982.  
  983. #ifdef macintosh
  984.  
  985. Tcl_VarEval(Tcl_Interp *interp,...)
  986. {
  987.  
  988. #else
  989.  
  990. int
  991. #ifndef lint
  992. Tcl_VarEval(va_alist)
  993. #else
  994. Tcl_VarEval(interp, p, va_alist)
  995.     Tcl_Interp *interp;        /* Interpreter in which to execute command. */
  996.     char *p;            /* One or more strings to concatenate,
  997.                  * terminated with a NULL string. */
  998. #endif
  999.     va_dcl;
  1000. {
  1001.     Tcl_Interp *interp;
  1002.  
  1003. #endif
  1004.  
  1005.     va_list argList;
  1006. #        define FIXED_SIZE 200
  1007.     char fixedSpace[FIXED_SIZE+1];
  1008.     int spaceAvl, spaceUsed, length;
  1009.     char *string, *cmd;
  1010.     int result;
  1011.  
  1012.     /*
  1013.      * Copy the strings one after the other into a single larger
  1014.      * string.  Use stack-allocated space for small commands, but if
  1015.      * the commands gets too large than call ckalloc to create the
  1016.      * space.
  1017.      */
  1018.  
  1019. #ifdef macintosh
  1020.     va_start(argList, interp);
  1021. #else
  1022.     va_start(argList);
  1023. #endif
  1024.  
  1025. #ifndef macintosh
  1026.     interp = va_arg(argList, Tcl_Interp *);
  1027. #endif
  1028.  
  1029.     spaceAvl = FIXED_SIZE;
  1030.     spaceUsed = 0;
  1031.     cmd = fixedSpace;
  1032.     while (1) {
  1033.     string = va_arg(argList, char *);
  1034.     if (string == NULL) {
  1035.         break;
  1036.     }
  1037.     length = strlen(string);
  1038.     if ((spaceUsed + length) > spaceAvl) {
  1039.         char *_new;
  1040.  
  1041.         spaceAvl = spaceUsed + length;
  1042.         spaceAvl += spaceAvl/2;
  1043.         _new = ckalloc((unsigned) spaceAvl);
  1044.         memcpy((VOID *) _new, (VOID *) cmd, spaceUsed);
  1045.         if (cmd != fixedSpace) {
  1046.         ckfree(cmd);
  1047.         }
  1048.         cmd = _new;
  1049.     }
  1050.     strcpy(cmd + spaceUsed, string);
  1051.     spaceUsed += length;
  1052.     }
  1053.     va_end(argList);
  1054.     cmd[spaceUsed] = '\0';
  1055.  
  1056.     result = Tcl_Eval(interp, cmd, 0, (char **) NULL);
  1057.     if (cmd != fixedSpace) {
  1058.     ckfree(cmd);
  1059.     }
  1060.     return result;
  1061. }
  1062.